home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
cool
/
cool.lha
/
ice
/
papers
/
cool-core.ms
next >
Wrap
Text File
|
1991-09-04
|
45KB
|
886 lines
.nr PS 10
.nr VS 12
.nr PD .7v
.nr LL 6.5i
.TL
COOL \*- C++ Object-Oriented Library
.AU
Mary Fontana
LaMott Oren
.AI
Texas Instruments Incorporated
Computer Science Center
Dallas, TX
.AU
Martin Neath
.AI
Texas Instruments Incorporated
Information Technology Group
Austin, TX
.NH 1
Introduction
.LP
The C++ Object-Oriented Library (COOL) is a collection of
classes, templates, and macros for use by C++ programmers writing complex
applications. It raises the level of abstraction for the programmer to
concentrate on the problem domain, not on implementing base data structures,
macros, and classes. In addition, COOL also provides a system independent
software platform on top of which applications are built, since COOL
encapsulates such system specific functionality as date/time and exception
handling. This paper discusses the following COOL features:
.ID
\(bu Preprocessor and macros
\(bu Parameterized templates
\(bu Symbols and Packages
\(bu Polymorphic management
\(bu Exception handling
\(bu Coding style and conventions
\(bu Class hierarchy and overview
.DE
COOL is the first piece of what is expected to be an ever changing and
growing C++ class library. As such, some constraints will be necessary in order
to achieve compatible and seamless integration of new or modified features.
This paper outlines the major technologies and conventions that can be used and
followed to allow this to happen. This paper should be used as an aid in
understanding the COOL library, its organization, structure, and layout.
It assumes the reader to have a working knowledge of C++[1]. For more detailed
information and examples on each topic, the reader is referred to the
appropriate section(s) of the COOL User's manual[2].
.NH 1
Preprocessor and Macros
.LP
The COOL macro facility is an extension to the standard ANSI C macro
preprocessing functions available with the #define statement. The COOL
preprocessor is a modified tokenizing ANSI C preprocessor that allows a
programmer to define powerful extensions to the C++ language in an unobtrusive
manner. This enhanced preprocessor is portable and compiler independent and can
execute arbitrary filter programs or macro expanders on C++ code fragments.
Macros such as those that support parameterized templates are implementations
of theoretical design papers published by Bjarne Stroustrup[3]. Others provide
significant language features and enhanced power for the programmer heretofore
unavailable with conventional C++ implementations. It is important to note,
however, that once a macro is expanded, the resulting code is conventional C++
2.0 syntax acceptable to any conforming C++ translator or compiler[4].
The COOL preprocessor is supplied as part of the library and is the point at
which all language and computing enhancements available in COOL are
implemented. The proposed draft ANSI C standard indicates that extensions and
changes to the language and/or features implemented in a preprocessor/compiler
should be made by using the #pragma statement. The COOL preprocessor follows
this recommendation and uses this as the means by which all macro extensions
are made. The #pragma defmacro statement is the single hook through which
features such as the class macro, parameterized templates, and polymorphic
enhancements have been implemented.
The COOL preprocessor is derived from and based upon the DECUS ANSI C
preprocessor made available by the DEC User's group in the public domain and
supplied on the X11R3 source tape from MIT. It complies with the draft ANSI C
specification with the exception that trigraph sequences are not implemented.
In addition to support for COOL macro processing discussed above, the
preprocessor has several new command line options to support C++ comments and
includes file debugging aids.
The #pragma defmacro statement is implemented in the COOL C/C++ preprocessor
and is the single hook through which features such as the class macro,
parameterized templates, and polymorphic enhancements have been implemented.
The defmacro facility provides a way to execute arbitrary filter programs on
C++ code fragments passing through the preprocessor. When a defmacro style
macro name is found, the name and everything until the delimiter (including all
matching {} [] () <> #" `' and comments found along the way) is piped onto the
standard input stream of the indicated program or filter procedure. The
procedure's standard output is scanned by the preprocessor for further
processing. The expansion replaces the macro call and is passed onto the
compiler for parsing.
The implementation of a defmacro can be either external to the preprocessor (as
in the case of files and programs) or internal to the preprocessor. For
example, the template, declare and implement macros that implement
parameterized types is internal to the preprocessor to provide a more efficient
implementation. The defmacro facility first searches for a file or program in
the same search path as that used for include files. If a match is not found,
an internal preprocessor table is searched. If a match is still not found, the
error message, "Error: Cannot open macro file [xxx]", where xxx is the name as
it appears in the source code, is sent to the standard error stream. The
fundamental COOL macros are defined with defmacro in the header file
<COOL/misc.h>, which must be included in any COOL C++ source file.
Porting COOL to a new platform or operating system starts with the
preprocessor. The preprocessor contains support for the defmacro statement and
also implements several important macros internally for efficiency and
performance considerations. In addition, a powerful macro language, simplifying
many library functions is available via the \fBMACRO\fR keyword.
\fBMACRO\fR implements an enhanced #define syntax that supports
multiple line, arbitrary length, nested macros and preprocessor directives with
positional, optional, optional keyword, required keyword, rest, and body
arguments. Many of the COOL features would be very difficult, if not
impossible, to implement without this enhanced macro language.
.NH 1
Parameterized Templates
.LP
The development and successful deployment of application libraries such as COOL
is made easier and more useful by a language feature called
parameterization. Parameterized templates allow a programmer to design and
implement a class template without specifying the data type. The user
customizes the template to produce a specific class by indicating the type in a
program. Several versions of the same parameterized template (each with a
different type) can exist in a single application. Parameterized templates can
be thought of as meta-classes in that only one source base needs to be
maintained to support numerous variations of a type of class.
Regardless of the type of object a parameterized class is to manipulate, the
structure and organization of the class and the implementation of the member
functions are the same for every version of the class. For example, a
programmer providing a vector class knows that there will be several member
functions such as insert, remove, print, sort, and so on that apply to every
version of the class. By parameterizing the arguments and return values from
the various member functions, the programmer provides only one implementation
of the vector class. The user of the class then specifies the type of vector at
compile-time.
An important and useful type of parameterized template is known as a container
class. A container class is a special kind of parameterized class where you put
objects of a particular type. For example, the \fBVector\fR<\fIType\fR>,
\fBList\fR<\fIType\fR>, and \fBHash_Table\fR<\fIKType,Vtype\fR> classes are
container classes because they contain a set of programmer-defined data types.
Since container classes are so commonplace in many applications and programs,
parameterized container classes provide a mechanism to maintain one source base
for several versions of very useful data structures. COOL supplies several
common container class data structures that can be used in many typical
application scenarios.
Each of the COOL parameterized container classes support the notion of a
built-in iterator that maintains a current position in the container and is
updated by various member functions. These member functions allow you to move
through the collection of objects in some order and manipulate the element
value at that position. This might be used, for example, in a function that
takes a pointer to a generic object that is a type of container object. The
function can iterate through the elements in the container by using the current
position member functions without needing to know whether the object is a
vector, a list, or a queue.
In addition to this built-in current position mechanism, COOL provides
support for multiple iterators over the same class by using the \fBIterator
\fR<\fIType\fR> class. For example, a programmer may need to
write a function that moves through the elements of a container class and, at
some point, needs to save the current position and begin processing elements at
another location. After a period of time, the secondary processing terminates,
at which point flow of control returns to the previous stopping point where the
current position is restored from the iterator object and processing continues.
A programmer uses the COOL C++ Control program (CCC), instead of the normal CC
procedure, to control the compilation process. This program provides all of the
capabilities of the original CC program with additional support for the COOL
preprocessor, parameterized types, and the COOL macro language. CCC controls
and invokes the various components of the compilation process. In particular,
however, it looks for command line arguments specific to the parameterized
template process and processes them accordingly as suggested by Stroustrup in
his design paper[2]. Other options and arguments are passed on to the system
C++ compiler control program.
.NH 1
Symbols and Packages
.LP
A package provides a relatively isolated namespace for various COOL components
called symbols. A symbol that is owned by a particular package is said to be
interned in that package. In general, the term interned means that a
particular object is uniquely identifiable in some context. When a symbol is
interned, it becomes uniquely identifiable by the symbol name within a
namespace context. The package system provides logical groupings of symbols
supporting relationships established between named objects and the values they
contain. Although the notion of symbols being grouped into packages is fairly
straightforward, the nature of the relationships that can exist between
packages and the way in which they establish a namespace can be quite complex.
COOL provides several kinds of macros to simplify the usage and
manipulation of symbols and packages.
A symbol is a data object that defines a relationship between a name, a
package, a value, and a property list. The name is a character string used to
identify the symbol. Once a name is established for a symbol, it may not be
changed. The value field is used to refer to some C++ object. Property lists
are lists of alternating names and values. The property list allows the
programmer to associate supplemental attributes with a symbol. Initially, the
property list for a symbol is empty.
The Symbol and Package classes implement the fundamental COOL symbolic
computing support as standard C++ classes. The Symbol class implements the
notion of a symbol that has a name with an optional value and property list.
Symbols are interned into a package, which is merely a mechanism for
establishing separate name spaces. The Package class implements a package as a
hash table of symbols and includes public member functions for adding,
retrieving, updating, and removing symbols.
COOL supports efficient and flexible symbolic computing by providing symbolic
constants and run-time symbol objects[5]. You can create symbolic constants at
compile-time and dynamically create and manipulate symbol objects in a package
at run-time by using any of several simple macros or by directly manipulating
the objects. Symbols and packages in COOL manage error message textual
descriptions with translations, provide polymorphic extensions to C++ for
object type and contents queries, and support sophisticated symbolic computing
not normally available in conventional languages.
.NH 1
Polymorphic Management
.LP
C++ version 2.0 as specified in the AT&T language reference manual[6]
implements virtual member functions that delay the binding of an object to a
specific function implementation until runtime. This delayed (or dynamic)
binding is useful where the type of object might be one of several kinds, all
derived from some common base class but requiring a specialized implementation
of a function. The classic example is that of a graphics editor where, given a
base class graphic_object from which square, circle, and triangle are derived,
specialized virtual member functions to calculate the area are provided. In
such a system, a programmer can write a function that takes a graphic_object
argument and determine its area without knowing which of all the possible kinds
of graphical objects the argument really is.
This dynamic binding capability of C++, while powerful and providing greater
flexibility than most other conventional programming languages, is still not
enough for some types of problems. Highly dynamic languages such as
Lisp allow the programmer to delay almost all decisions until runtime[7]. In
addition, facilities for querying an object at runtime to determine its type or
request a list of all possible member functions available are often present.
These kinds of features are commonly used in many symbolic computing and
complex knowledge-intensive operations management problems tackled today.
COOL supports enhanced polymorphic management capabilities with a
programmer-selectable collection of macros, classes, symbolic constants,
run-time symbolic objects, and dynamic packages[1]. This is facilitated by the
Generic class that, combined with macros, symbols, and packages, provides
efficient run-time object type checking, object query, and enhanced polymorphic
functionality unavailable in the C++ language.
The Generic class is inherited by most other COOL classes and manipulates
lists of symbols to manage type information. Generic adds run-time type
checking and object queries, formatted print capabilities, and a describe
mechanism to any derived class. The COOL class macro (discussed below)
automatically generates the necessary implementation code for these member
functions in the derived classes. A significant benefit of this common base
class is the ability to declare heterogenous container classes parameterized
over the Generic* type. These classes, combined with the current position and
parameterized iterator class, lets the programmer manipulate collections of
objects of different types in a simple, efficient manner.
One of the simplest and most useful features facilitated by Generic is the
runtime type checking capability. The type_of() and is_type_of() virtual member
functions accomplish this kind of run-time type query for an object that is
derived at some point from the COOL Generic class. Type determination and
function dispatch can become quite tedious, however, if there are many types of
objects. Ideally, each would be derived from a common base and include support
for a virtual member function for each important operation that might be
required. However, it is sometimes not feasible to have such a situation,
especially with a high number of objects obtained from several sources. An
alternate scheme similar to the one mentioned above is the type_case macro,
analogous to the C++ switch statement. It gathers all possible type cases and
allows the user to symbolically dispatch on the type of object represented by
the case statements. This automates some of the symbol collection and
manipulation required with the earlier mechanism.
The class keyword is implemented as a COOL macro to add symbolic computing
abilities to class definitions. It takes a standard C++ class definition and,
if the class contains Generic somewhere in its inheritance hierarchy, generates
member functions for support of run-time type checking and query. In addition,
a symbol for the derived Generic class type is added to the COOL global symbol
package SYM. The actual code which is expanded in a class definition and after
a class definition is controlled by the classmac macro discussed below.
The classmac macro provides two hooks as a point of customization by
user defined macros. A combination of data members and member functions of a
class definition are passed as arguments to macros that can be changed or
customized by the application programmer. The COOL Generic class uses the data
member hook to implement the map_over_slots() member function. There may be
more than one classmac macro hook specified by the programmer. COOL has
several, and other user-defined macros are simply chained together in a calling
sequence ordered according to the order of definition. Each classmac macro
defines how the class macro should expand the class definition. The class
macro does not actually generate the code itself. This is defined in
user-modifiable header files that specify a classmac macro. For example, a
general purpose mechanism that automatically creates accessor member functions
to get and set each data member can be created by defining a classmac macro
that is attached to the data member hook of the class macro . No changes to the
COOL preprocessor are required.
The member functions added by Generic and the class macro to derived COOL
classes manipulate symbols stored in the global SYM package. These symbols
reflect the inheritance tree for a specific class. They may have optional
property lists containing information associating supported member functions
and their respective argument lists. User-defined classes derived from Generic
are also automatically supported in an identical fashion, resulting in
addition symbols in the global symbol package. As discussed earlier, these
symbols must have storage allocated for them and code to initialize the package
at program startup time. This is managed by the COOL file symbols.C that should
be compiled and linked with every application that uses COOL. An automated
method for insuring correct package setup and symbol initialization is
accomplished by establishing the correct dependency in an application make
file.
.NH 1
Exceptions
.LP
In COOL, program anomalies are known as exceptions. An exception can be
an error, but it can also be a problem such as impossible division or
information overflow. Exceptions can impede the development of object-oriented
libraries. Exception handling offers a solution by providing a mechanism to
manage such anomalies and simplify program code. The COOL exception
handling scheme is a raise, handle, and proceed mechanism similar to the Common
Lisp Condition System[8]. When a program encounters an anomaly that is
often (but not necessarily) an error, it can:
.ID
\(bu Represent the anomaly in an object called an exception
\(bu Announce the anomaly by raising the exception
\(bu Provide solutions to the anomaly by defining and establishing handlers
\(bu Proceed from the anomaly by invoking a handler function
.DE
The COOL exception handling facility[9] provides an exception class
(Exception), an exception handler class (Excp_Handler), a set of predefined
exception subclasses (Warning,, Fatal, System_Error, System_Signal, and Error),
and a set of predefined exception handler functions. In addition, the macros
EXCEPTION, RAISE, STOP, and VERIFY allow the programmer to easily create and
raise an exception at any point in a program.
When an exception is raised (through macros RAISE or STOP, for example), a
search begins for an exception handler that handles this type of exception. An
exception handler, if found, deals with the exception by calling its exception
handler function. The exception handler function can correct the exception and
continue execution, ignore the exception and resume execution, or end the
program. In COOL, an exception handler for each of the predefined exception
types exists on the global exception handler stack.
An exception handler invokes a specific exception handler function for a
specific type of exception. Handling an exception means proceeding from the
exception. An exception handler function could report the exception to
standard error and end the program, or drop a core image for use by the
programmer with a debugger. Another way of proceeding is to query the user for
a fix, store the fix in the exception object, and return to where the exception
was raised. When an exception handler object is declared, is is placed on the
top of a global exception handler stack. When an exception is raised, a call
searches for a handler. The handler search starts at the top of the exception
handler stack.
There are six predefined exception type classes provided as part of COOL. The
exception class is the base class from which specialized exception subclasses
are derived. Derived from Exception are Warning, System_Signal, Fatal and
Error. From the Error class, the System_Error and Verify_Error classes are
derived. The default exception handlers are called only if no other exception
handler is established and available when an exception is raised. COOL
offers users the option of defining their own exception types. Such types can
be derived from the Exception class of one of the derived exception types. All
user-defined exception classes should have public data slots.
The COOL exception handling facility provides several macros which simplify the
process of creating, raising, and manipulating exceptions. These macros are
implemented with the COOL macro facility. The EXCEPTION macro simplifies the
process of creating an instance of a particular type of exception object. The
RAISE macro allows the programmer to easily raise an exception and search for
an exception handler. The STOP macro is similar to the the RAISE macro, except
that it guarantees to end the program if the exception is not handled. The
VERIFY macro raises an exception if an assertion for some particular expression
evaluates to FALSE. Finally, the IGNORE_ERRORS macro provides a mechanism to
ignore an exception raised while executing a body of statements.
The COOL exception handling mechanism is similar in several ways to that
proposed by Koenig and Stroustrup[10]. Their try statement and catch clauses
can be implemented by using a COOL exception handler with the system functions
\fBsetjmp\fR and \fBlongjmp\fR. In addition, both designs treat exceptions as
objects that are instantiated and passed as arguments to handler functions. The
AT&T proposal proposes a grouping of exception objects as a mechanism for
organizing exceptions into groups similar to the compile-time mechanism for
organizing classes into hierarchies. COOL, on the other hand, maintains an
exception derivation hierarchy and uses some of the COOL symbolic computing
facilities for run-time type checking and query. A grouping of exception names
similar to the AT&T proposal is currently being implemented where alias name(s)
may be defined for an exception object. For example, rather than defining a new
exception class derived from Error, an Error exception can be raised with the
specified alias/group name(s) passed as an argument. This is expected to reduce
the need for many different types of exception classes whose only difference is
the type name.
.NH 1
Coding Style and Conventions
.LP
A standard source code style allows several programmers to easily maintain and
understand each other's code because additional semantic information can be
inferred from a section's format and style. In addition, a single style
presents a more coherent, professional software package for potential source
code users. This is particularly important for COOL, since parameterized
templates require complete access to all source code. Finally, one of the
foundations of object-oriented programming is code reuse. This is much easier
if a programmer is able to browse through source code and understand its
organization and layout. The COOL source code addresses the following C++
coding style conventions:
.ID
\(bu Variable and class naming conventions
\(bu Organization and contents of class header files
\(bu Private/Protected/Public data members
\(bu Source code documentation
\(bu Source code indentation and layout
\(bu Error message text resource package
\(bu Regression test suite
\(bu Source code system independence
\(bu Build procedure
.DE
.NH 2
Naming Conventions
.LP
A prime objective for a naming convention is allowing programmers to recognize
what sort of component a name refers to. Another goal is using meaningful
names, which has not typically been done in C applications. The following
naming conventions are used throughout the COOL source code. The reader is
strongly encouraged to follow the same guidelines:
.RS
\(bu Directory, .C, and .h file names should be the same or close to the
class being defined and the declaration and implement files should be in a
single directory. For example, the String class is defined and implemented in
the files String.h and String.C and contained in the ~COOL/String subdirectory.
.RE
.RS
\(bu Class, struct, and typedef names should be capitalized with the words
separated by underscores:
.ID
class Generic_Window { ... };
struct String_Layout { ... };
typedef int Boolean;
.DE
.RE
.RS
\(bu All function names should be lowercase with each word separated by an
underscore character:
.ID
void my_fun (int foo);
char* get_name (ostream&);
.DE
.RE
.RS
\(bu Predicate functions should begin with is_:
.ID
Boolean is_type_of (int);
.DE
.RE
.RS
\(bu Variable and data member names should be lowercase with words separated
by underscores:
.ID
int ref_count;
char* name;
.DE
.RE
.RS
\(bu Global and static variables should be appended with _g or _s,
respectively:
.ID
int node_count_g;
static char* version_s;
.DE
.RE
.RS
\(bu Preprocessor statements and MACRO names should be uppercase:
.ID
#define ABS ((x < 0) ? (-x) : x)
.DE
.RE
.RS
\(bu Constants (const) declarations should be uppercase:
.ID
const int FALSE=0;
const int TRUE=!FALSE;
.DE
.RE
.NH 2
Class Header File Organization
.LP
All header files defining the structure of a
class or parameterized template should be organized into sections in the
following order:
.ID
\(bu Included files and typedefs necessary for the class.
\(bu Definition of private data members.
\(bu Declaration of private member functions and friends.
\(bu Definition of protected data members.
\(bu Declaration of protected member functions and friends.
\(bu Declaration of public member functions and friends.
\(bu Inline member functions of the class follow the class definition.
\(bu Other member/friend function definitions are in a separate file.
.DE
In general, only the data member definitions and function prototypes of the
member functions and friend functions should appear in the class construct.
This separates the implementation from the specification and reduces clutter.
Define inline functions after the class {...}; statements. In addition, the
keyword inline should appear in both the class definition and in the actual
implementation as a documentation aid. The optional private keyword usage is
explicitly stated. Finally, avoid multiple instances of scoped sections: There
should be no more than one each of the private, protected, and public labels.
.NH 2
Private, Protected, and Public Data
.LP
In general, class data should be encapsulated in either the private or
protected sections. Data specific to a particular class with no use for
possible derived classes should be located in the private section. Data located
in the protected section might include such things as configuration or
adjustment data members that a derived class might want to monitor or change.
No COOL classes contain public data, and the user should not declare such data.
Aside from being bad object-oriented programming style, classes with public
data cannot be made persistent and stored in the OODB. The one exception to
this standard are the derived exception classes which may require public data
members in order to allow query and/or update of alternate values.
.NH 2
Documentation
.LP
Documentation of all files is very important. Terseness should be the general
rule for all header files and completeness the rule for all code files.
Parameterized templates have a single header/source file and all documentation
should be located there. If in doubt, more documentation is better than less
documentation. A high-level abstract at the top of each file should provide a
description of the file's functionality. Class header files should also
contain a brief description of the public interface.
Each function in a source code file should have a preceding block comment
specifying the input and output parameters as well as giving a brief synopsis
of the functionality. For complex inline definitions in header files, a block
comment of this type should only be used when the purpose is not obvious
because these comments do not appear in the code file. Since most inline
functions contain trivial code (usually providing an accessor to some private
data member), comment requirements for inline function can be relaxed.
All source code should be commented every few source lines. Specifically, large
block comments every 100 lines is unacceptable. No comment should contain
operating system specific names or terms unless that section of code is truly
specific. When this is necessary, the code should be surrounded by conditional
compilation constructs. These are handled by the preprocessor relative to that
specific operating system.
Finally, documentation in the form of a man page should be written for every
class. Layout and organization will be as that with the -man macro package
available for nroff(1)/troff(1). Section names and requirements for a class man
page include Name, Synopsis, Base Class, Friend Classes, Description,
Constructors (public or protected as necessary), Protected Member Functions
(when appropriate), Public Member Functions, Files, See Also, and Bugs (when
necessary). Introductory and high-level material can and should also be
documented.
.NH 2
Source Code Indentation
.LP
Indentation and source code structure is relaxed, but it is suggested that the
programmer use the C++ mode available for GNU Emacs and supplied with COOL. In
general, statements should be restricted to one line with indentation
reflecting block and scoping visibility. Location of such items as braces,
spacing around parentheses, and so on is left up to the programmer. If the C++
mode is used, whole regions can be marked and indented appropriately, providing
a simple means by which all source code can be brought into the same format.
.NH 2
Error Message Resource Package
.LP
All error message text strings in an application should use the ERR_MSG package
available in COOL. The COOL exception handling scheme automatically uses
this package insuring that all text strings associated with error messages are
stored as the value of a symbol. All error message symbols are
automatically processed and located in one file, thus facilitating easy update
or configuration. In particular, a language translation can be added to the
property list of each symbol entry, providing an efficient and convenient means
for internationalizing the text messages in an application.
.NH 2
Regression Test Suite
.LP
Each new or modified class contained in or added to COOL must also include
a standalone test program. This should fully exercise all features and
functions and report success or failure via the test macros contained in the
~COOL/include/test.h header file. This test program is used in regression tests
for new releases and ports to other software platforms to insure a complete and
working implementation.
.NH 2
Source Code System Independence
.LP
COOL places great importance upon system independent code and features. As
such, system-specific functions should be surrounded with #if preprocessor
directives where appropriate. In general small performance sacrifices in
implementation are preferred if system independence and portability is
improved.
.NH 2
Build Procedure
.LP
COOL contains a modified Imake utility from the MIT X11R3 source tape that
implements a system-independent build procedure. This should be used for all
new classes and source code. Imake provides configuration and rules files for
localization and/or customization of system build utilities and commands to aid
in porting activities to other operating systems and hardware platforms.
.NH 1
Class Hierarchy
.LP
The C++ Object-Oriented Library (COOL) class hierarchy implements a rather
flat inheritance tree, as opposed to the deeply nested SmallTalk model. All
complex classes are derived from the Generic class, to facilitate run-time type
checking and object query Simple classes are not derived from Generic due to
space efficiency concerns. The parameterized container classes all inherit from
a base class that results in shared type-independent code. This reduces code
replication when a particular type of container is parameterized several times
for different objects in a single application. The COOL class hierarchy is as
follows:
.ID
Pair\fR<\fIT1,T2\fR>
Range
Range\fR<\fIType\fR>
Rational
Complex
Generic
String
Gen_String
Regexp
Vector
Vector\fR<\fIType\fR>
Association\fR<\fIPair\fR<\fIT1,T2\fR>\fR>
List_Node
List_Node\fR<\fIType\fR>
List
List\fR<\fIType\fR>
Date_Time
Timer
Bit_Set
Exception
Warning
Error
System_Error
Fatal
System_Signal
Verify_Error
Excp_Handler
Jump_Handler
Hash_Table
Set
Hash_Table\fR<\fIKey,Value\fR>
Package
Matrix
Matrix\fR<\fIType\fR>
Queue
Queue\fR<\fIType\fR>
Random
Stack
Stack\fR<\fIType\fR>
Symbol
Binary_Node
Binary_Node\fR<\fIType\fR>
Binary_Tree
Binary_Tree\fR<\fIType\fR>
AVL_Tree\fR<\fIType\fR>
N_Node\fR<\fIType\fR>
D_Node\fR<\fIType\fR>
N_Tree\fR<\fIType,Node,nchild\fR>
.DE
.NH 2
String Classes
.LP
The String class provides dynamic, efficient strings for a C++ application. The
intent is to provide efficient char*-like functionality that frees the
programmer from worrying about memory allocation and deallocation problems, yet
retains the speed and compactness of a standard char* implementation. All
typical string operations including concatenation, case-sensitive and
case-insensitive lexical comparison, string search, yank, delete, and
replacement are provided.
The Regexp class provides a convenient mechanism to present regular expressions
for complex pattern matching and replacement and utilizes the built-in char*
data type. The Gen_String class provides general-purpose, dynamic strings for a
C++ application with support for reference counting, delayed copy, and regular
expression pattern matching. The intent is to provide a sophisticated character
string function for the application programmer. The Gen_String class combines
the functions of the String and Regexp classes, along with reference counting
and self-garbage collection, to provide advanced character string manipulation.
.NH 2
Number Classes
.LP
The COOL number classes are a collection of numerically-oriented classes that
augment the built-in numerical data types to provide such features as extended
precision, range-checked types, and complex numbers. The Random class
implements five variations of random number generators. The Complex class
implements the complex number type for C++ and provides basic arithmetic and
trigonometric functions, conversion to and from built-in types, and simple
arithmetic exception handling. The Rational class implements an extended
precision rational data type for inadequate round-off and/or truncation results
from the built-in numerical data types. Finally, the parameterized \fBRange
\fR\fR<\fI\fIType\fR\fR> class enables arbitrary user-defined ranges to be implemented in C++ classes.
Typically, this is used with other number classes to select a range of valid
values for a particular numerical type.
.NH 2
System Interface Classes
.LP
System Interface classes include classes for calculating the date and time in
different timezones and countries and measuring the time duration between two
points in some application program. The Date_Time class executes time
zone-independent date and time functions. This class also supports all time
zones in the world, along with several special cases requiring alternate
handling based upon political or daylight saving time differences. The Timer
class is publicly derived from Generic and provides an interface to system
timing. It allows a C++ program to record the time between a reference point
(mark) and now.
.NH 2
Ordered Sequence Classes
.LP
The ordered sequence classes are a collection of basic data structures that
implement sequential access data structures as parameterized classes, thus
allowing the user to customize a generic template to create a user-defined
class. The \fBVector\fR\fR<\fI\fIType\fR\fR> class implements single dimension
vectors of a user-specified type. The \fBStack\fR\fR<\fI\fIType\fR\fR> class
implements a conventional first-in, last-out data structure, similar to the
\fBQueue\fR\fR<\fI\fIType\fR\fR> class but it implements a conventional
first-in, first-out data structure. These two classes each hold a
user-specified data type. The \fBMatrix\fR\fR<\fI\fIType\fR\fR> class
implements two-dimensional arithmetic matrices for a user-specified numeric
data type. The vector, stack, and queue classes can be dynamic in size.
.NH 2
Unordered Sequence Classes
.LP
The unordered sequence classes are a collection of basic data structures that
implement random access data structures as parameterized classes, thus allowing
the user to customize a generic template to create a specific user-defined
class. The \fBList\fR<\fIType\fR> class implements Common Lisp style lists
providing a collection of member functions for list manipulation and
management. A list consists of a collection of nodes, each of which contains a
reference count, a pointer to the next node in the list, and a data element of
a user-specified type. The \fBPair\fR<\fIT1,T2\fR> class implements an
association between one object and another. The objects may be of different
types, with the first representing the key of the pair and the second
representing the value of the pair. The \fBAssociation\fR<\fIKtype,Vtype\fR>
class is privately derived from the \fBVector\fR<\fIType\fR> class and
implements a collection of pairs. The first of the pair is called the key and
the second of the pair is called the value. The
\fBHash_Table\fR<\fIKtype,VType\fR> class implements hash tables of
user-specified types for the key and the value.
.NH 2
Set Classes
.LP
The set classes implement two basic data structures for random access set
operations as parameterized classes, thus allowing the user to customize a
generic template to create a specific user-defined class. The
\fBSet\fR<\fIType\fR> class implements random access sets of objects of a
user-specified type using the parameterized type capability of C++. Classical
set operations such as union, intersection, and difference are available. The
\fBSet\fR<\fIType\fR> class is publicly derived from the
\fBHash_Table\fR<\fIKType,VType\fR> class and is dynamic in nature. The
Bit_Set class implements efficient bit sets. These bits are stored in an
arbitrary length vector of bytes (unsigned char) large enough to represent the
specified number of elements. Elements can be integers, enumerated values,
constant symbols from the enumeration package, or any other type of object or
expression that results in an integral value.
.NH 2
Node and Tree Classes
.LP
The node and tree classes are a collection of basic data structures that
implement several standard tree data structures as parameterized classes, thus
allowing the user to customize a generic template to create a specific
user-defined class. The \fBBinary_Node\fR<\fIType\fR> class implements
parameterized nodes for binary trees. The \fBBinary_Tree\fR<\fIType\fR> class
implements simple, dynamic, sorted sequences in a tree where each node has two
subtree pointers. The \fBAVL_Tree\fR<\fIType\fR> class implements
height-balanced, dynamic, binary trees. The \fBAVL_Tree\fR<\fIType\fR> class is
publicly derived from the \fBBinary_Tree\fR<\fIType\fR> class.
The \fBN_Node\fR<\fIType,nchild\fR> class implements parameterized nodes of a
static size for n-ary trees. This node class is parameterized for both the type
and some initial number of subtrees that each node may have. The constructors
for the \fBN_Node\fR<\fIType,nchild\fR> class are declared in the public
section to allow the user to create nodes and control the building and
structure of an n-ary tree where the ordering can have a specific meaning, as
with an expression tree. The \fBD_Node\fR<\fIType,nchild\fR> class implements
parameterized nodes of a dynamic size for n-ary trees. This node class is
parameterized for the type and some initial number of subtrees that each node
may have. The \fBD_Node\fR<\fIType,nchild\fR> class is dynamic in the sense
that the number of subtrees allowed for each node is not fixed.
\fBD_Node\fR<\fIType,nchild\fR> uses the \fBVector\fR<\fIType\fR> class,
supporting run-time growth characteristics.
The \fBN_Tree\fR<\fINode,Type,nchild\fR> class implements n-ary trees,
providing the organizational structure for a tree (collection) of nodes, but
knowing nothing about the specific type of node used.
\fBN_Tree\fR<\fINode,Type,nchild\fR> is parameterized over a node type, a data
type, and subtree count, where the node specified must have a data member of
the same Type as the tree class. The subtree count indicates the number of
possible subtree pointers (children) from any given node. Two node classes are
provided, but others can also be written.
.NH 1
Status of COOL
.LP
COOL is currently up and running on a Sun SPARCstation 1 (TM) running
SunOS (TM) 4.x,
.FS
SunOS and SPARCstation 1 are trademarks of Sun Microsystems, Inc.
.FE
a TI System 1500 running TI System V,
a PS/2 model 70 running SCO XENIX\(rg
.FS
XENIX is a registered trademark of Microsoft Corporation.
.FE
2.3, a PS/2 (TM)
.FS
PS/2 is a trademark of International Business Machines Corporation.
.FE
model 70 running OS/2 1.1, and
a MIPS running RISC/os 4.0. The SPARC and MIPS ports utilize the AT&T C++
translator (cfront) version 2.0 and the XENIX and OS/2 ports utilize the
Glockenspiel translator with the Microsoft C compiler.
.NH 1
References
.LP
.IP [1]
Stanley Lippman,
.I
C++ Primer,
.R
Addison-Wesley, Reading, MA, 1989.
.IP [2]
Texas Instruments Incorporated,
.I
COOL User's Guide,
.R
Information Technology Group, Austin, TX. Internal Original Issue January 1990.
.IP [3]
Bjarne Stroustrup,
.I
Parameterized Types for C++,
.R
Proceedings of the USENIX C++ Conference, Denver, CO, October 17-21, 1988,
pp. 1-18.
.IP [4]
Mary Fontana, Martin Neath and Lamott Oren,
.I
A Sophisticated C++ Macro Facility,
.R
Information Technology Group, Austin, TX. Internal Original Issue January 1990.
.IP [5]
Mary Fontana, Martin Neath and Lamott Oren,
.I
Symbolic Computing for C++,
.R
Information Technology Group, Austin, TX. Internal Original Issue January 1990.
.IP [6]
AT&T Incorporated,
.I
C++ Language System Release 2.0,
.R
AT&T Product Reference Manual Select Code 307-146, 1989.
.IP [7]
Guy L. Steele Jr,
.I
Common LISP: The Language,
.R
Second Edition, 1990.
.IP [8]
Andy Daniels and Kent Pitman,
.I
Common Lisp Condition System Revision #18,
.R
ANSI X3J13 subcommittee on Error Handling, March 1988.
.IP [9]
Mary Fontana, Martin Neath and Lamott Oren,
.I
Exception Handling in COOL,
.R
Information Technology Group, Austin, TX. Internal Original Issue January 1990.
.IP [10]
Andrew Koenig and Bjarne Stroustrup,
.I
Exception Handling for C++,
.R
C++ At Work Conference, Boston, MA, November 6-8, 1989.